import { EventEmitter } from 'events';
import moment from 'moment';

export default class Socket {
    // ws状态
    private open: boolean = false;

    // 数据发送队列，连接未打开时暂存发送数据
    private sendQueue: any[] = [];

    private ws: WebSocket;

    
    private url: string;
    
    private reconnectLock: boolean = false;

    protected emitter: EventEmitter;

    public socketEmitter: EventEmitter;
    
    constructor(url: string) {
        this.emitter = new EventEmitter();
        this.socketEmitter = new EventEmitter();
        this.url = url;
        this.socketEmitter.on("open", () => {
            console.log(`${ this.url }连接成功！`);
            this.open = true;
            while (this.sendQueue.length !== 0) {
                const data = this.sendQueue.shift();
                if (data) {
                    this.send(data);
                }
            }
        });

        this.socketEmitter.on("message", (event) => {
            this.onMessage(event);
        });

        this.socketEmitter.on("close", (event) => {
            if (!this.reconnectLock) {
                this.sendQueue = [];
                console.log(`${ this.url }连接已断开！`);
                this.reconnect();
            }
            this.open = false;
        });

        this.init();
    }

    public init(): Promise<boolean> {
        this.ws = new WebSocket(this.url);

        return new Promise((resolve) => {
            this.ws.onopen = () => {
                resolve(true);
                this.socketEmitter.emit("open");
            };

            this.ws.onmessage = (event) => {
                this.socketEmitter.emit("message", event);
            };
    
            this.ws.onclose = () => {
                resolve(false);
                this.socketEmitter.emit("close", event);
            };
        });
    }

    public send(data: string | object) {
        if (this.open) {
            data = typeof data === "object" ? JSON.stringify(data) : data;
            this.ws.send(data);
        } else {
            this.sendQueue.push(data);
        }
    }

    public onMessage(event: MessageEvent) {
        try {
            const data = JSON.parse(event.data);
            this.emitter.emit(data.type, data);
        } catch (error) {
            console.error(error);
        }
    }

    public on(eventName: string, callback: (data: any) => any) {
        this.emitter.on(eventName, callback);
    }

    public removeListener(eventName: string, callback: (data: any) => any) {
        this.emitter.removeListener(eventName, callback);
    }

    // 断线重连
    public async reconnect(): Promise<void> {
        this.reconnectLock = true;
        this.socketEmitter.emit("reconnect");
        while (true) {
            console.log(`${ moment().format("YYYY-MM-DD hh:mm:ss") }: ${ this.url }尝试重连...`);
            if (await this.init()) {
                break;
            }
            await new Promise((resolve) => {
                setTimeout(resolve, 1000);
            });
        }
        this.socketEmitter.emit("reconnectEnd");
        this.reconnectLock = false;
    }
}